package com.lsh.payment.core.util;

import com.lsh.payment.core.exception.BusinessException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

/**
 * HTTP 请求工具类
 *
 * @author : miaozhuang
 * @version : 1.0.0
 * @date : 2016/8/24
 * @see : TODO
 */
public class HttpsClientUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpsClientUtil.class);

    private static RequestConfig requestConfig;
    private static final int MAX_TIMEOUT = 30000;

    static {

        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        // 在提交请求之前 测试连接是否可用
        requestConfig = configBuilder.build();
    }


    /**
     * 请求微信
     * @param apiUrl     请求url
     * @param xml        xml文本
     * @param mchid      商户号
     * @param path       证书路径
     * @return           返回结果
     */
    public static String doPostXml(String apiUrl, String xml, String mchid, String path) {

        String httpContent = null;
        HttpPost httpPost = new HttpPost(apiUrl);
        CloseableHttpResponse response = null;

        logger.info("[POST][URL] {}", apiUrl);
        CloseableHttpClient httpClient = null;
        try {
            httpClient = create(mchid, path);
            httpPost.setConfig(requestConfig);

            // 解决中文乱码问题
            StringEntity stringEntity = new StringEntity(xml, "UTF-8");
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("text/xml");
            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);

            logger.info("[POST][response] : {}", response.toString());

            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {

                HttpEntity entity = response.getEntity();
                httpContent = EntityUtils.toString(entity, "UTF-8");

            } else {

                logger.info("[response code] : {}", response.getStatusLine().getStatusCode());
            }

        } catch (IOException e) {
            logger.error("[http IOException] ", e);
        } catch (Exception e) {
            logger.error("[http Exception] ", e);
        } finally {

            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return httpContent;
    }


    private static CloseableHttpClient create(String mchid, String path) throws Exception {
        // Allow TLSv1 protocol only

        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                initSSLContext(mchid, path),
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }


    private static SSLContext initSSLContext(String mchid, String path) {

        if (StringUtils.isBlank(mchid)) {
            throw new IllegalArgumentException("【请确保商户号mchId已设置】");
        }

        if (StringUtils.isBlank(path)) {
            throw new IllegalArgumentException("【请确保证书文件地址keyPath已配置】");
        }

        InputStream inputStream = null;

        try {

            File file = new File(path);
            if (!file.exists()) {
                throw new BusinessException("【证书文件【" + file.getPath() + "】不存在！】");
            }

            inputStream = new FileInputStream(file);

            KeyStore keystore = KeyStore.getInstance("PKCS12");
            char[] partnerId2charArray = mchid.toCharArray();
            keystore.load(inputStream, partnerId2charArray);
            return SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
        } catch (IOException e) {
            throw new BusinessException("【证书文件读取错误，请核实！】", e);
        } catch (Exception e) {
            throw new BusinessException("【证书文件有问题，请核实！】", e);
        } finally {
            if (inputStream != null) {
                IOUtils.closeQuietly(inputStream);
            }
        }
    }


}
